﻿using LogLib;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace ComLib.ComFun
{
    public class ImageConverterCom
    {
        /// <summary>
        /// 设置256级灰度位图的调色板
        /// </summary>
        /// <param name="bitmap"></param>
        public static void SetColorPaletteOfGrayscaleBitmap(Bitmap bitmap)
        {
            PixelFormat pixelFormat = bitmap.PixelFormat;
            if (pixelFormat == PixelFormat.Format8bppIndexed)
            {
                ColorPalette palette = bitmap.Palette;
                for (int i = 0; i < palette.Entries.Length; i++)
                    palette.Entries[i] = Color.FromArgb(255, i, i, i);
                bitmap.Palette = palette;
            }
        }

        public static Bitmap ToThumbnail(Bitmap srcImg, Size newSize, float fDpi)
        {
            int w = newSize.Width;
            int h = newSize.Height;
            Bitmap newImg = new Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format24bppRgb);       
            try
            {
                newImg.SetResolution(fDpi, fDpi);
                using (Graphics graphic = Graphics.FromImage(newImg))
                {
                    graphic.CompositingQuality = CompositingQuality.HighQuality;
                    //设置高质量查值法
                    graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    //设置高质量，低速度呈现平滑程度
                    graphic.SmoothingMode = SmoothingMode.HighQuality;
                    //清空画布并以透明背景色填充
                    graphic.Clear(System.Drawing.Color.White);
                    graphic.DrawImage(srcImg,
                        new Rectangle(0, 0, w, h),
                        new Rectangle(0, 0, srcImg.Width, srcImg.Height),
                        System.Drawing.GraphicsUnit.Pixel);
                }
                return newImg;
            }
            catch (Exception ex)
            {
                Log.WriteException(ex.ToString());
                return null;
            }
        }

        public static void AdjustBitmapFileLength(Bitmap image, string strFileName, int minSize, int maxSize, out int modifyFlag)
        {
            modifyFlag = -99;
            long compression = 100;
            SaveImageAsJPEG(image, strFileName, compression);
            FileInfo fi = new FileInfo(strFileName);
            long maxLen = 1024 * maxSize;
            long minLen = 1024 * minSize;
            long length = fi.Length;
            if (length >= minLen && length <= maxLen)
            {
                modifyFlag = 0;
                return;
            }
            if (length > maxSize)
            {
                if (CompressImage(image, strFileName, minSize))
                {
                    modifyFlag = -1;
                    return;
                }               
            }
            if (length < minLen)
            {             
                ResizeImage(strFileName, maxSize);
                modifyFlag = 1;
                return;
            }
        }

        public static void SaveImageAsJPEG(Bitmap image, string strFileName, long compression)
        {
            ImageCodecInfo jpegIClinfo = null;
            ImageCodecInfo[] vImageCodecInfos = ImageCodecInfo.GetImageEncoders();
            EncoderParameters vEncoderParameters = new EncoderParameters(1);
            vEncoderParameters.Param[0] = new EncoderParameter(
                System.Drawing.Imaging.Encoder.Quality,
                compression);
            foreach (ImageCodecInfo vImageCodecInfo in vImageCodecInfos)
            {
                if (vImageCodecInfo.FormatDescription.ToLower() == "jpeg")
                {
                    jpegIClinfo = vImageCodecInfo;
                    break;
                }
            }
            image.Save(strFileName, jpegIClinfo, vEncoderParameters);      
        }

        public static bool CompressImage(Bitmap image, string strFileName, int maxSize)
        {
            long compression = 100;
            SaveImageAsJPEG(image, strFileName, compression);
            FileInfo fi = new FileInfo(strFileName);
            long maxLen = 1024 * maxSize;
            long length = fi.Length;
            while (compression > 0 && length > maxLen)
            {
                compression -= 1;
                SaveImageAsJPEG(image, strFileName, compression);
                FileInfo fiTemp = new FileInfo(strFileName);
                length = fiTemp.Length;
            }
            if (length > maxLen)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        public static byte[] CompressImage(Bitmap image, long compression)
        {
            ImageCodecInfo jpegIClinfo = null;
            ImageCodecInfo[] vImageCodecInfos = ImageCodecInfo.GetImageEncoders();
            EncoderParameters vEncoderParameters = new EncoderParameters(1);
            vEncoderParameters.Param[0] = new EncoderParameter(
                System.Drawing.Imaging.Encoder.Quality,
                compression);
            foreach (ImageCodecInfo vImageCodecInfo in vImageCodecInfos)
            {
                if (vImageCodecInfo.FormatDescription.ToLower() == "jpeg")
                {
                    jpegIClinfo = vImageCodecInfo;
                    break;
                }
            }
            byte[] imgArray = null;
            using(MemoryStream stream = new MemoryStream())
            {
                image.Save(stream, jpegIClinfo, vEncoderParameters); 
                imgArray = stream.ToArray();
            }
            return imgArray;  
        }

        public static void ResizeImage(string path, int minLen)
        {         
            int boundVal = (minLen + 2) * 1024;
            using (FileStream fs = new FileStream(path, FileMode.Append))
            {
                byte[] b = { 0x00 };
                while (fs.Length < boundVal)
                {
                    fs.Write(b, 0, b.Length);
                }
                fs.Flush();
            }
        }
        /// <summary>
        /// Copy a block of memory.
        /// </summary>
        /// 
        /// <param name="dst">Destination pointer.</param>
        /// <param name="src">Source pointer.</param>
        /// <param name="count">Memory block's length to copy.</param>
        /// 
        /// <returns>Return's the value of <b>dst</b> - pointer to destination.</returns>
        /// 
        [DllImport("ntdll.dll", CallingConvention = CallingConvention.Cdecl)]
        public static unsafe extern int memcpy(
            byte* dst,
            byte* src,
            int count);

        public static Bitmap Crop(Bitmap srcImage, Rectangle rec)
        {
            int width = rec.Width;
            int height = rec.Height;
            // create new image
            System.Drawing.Bitmap image = new Bitmap(width, height, PixelFormat.Format24bppRgb);

            // lock bitmap data
            BitmapData imageData = image.LockBits(
                new Rectangle(0, 0, width, height),
                ImageLockMode.ReadWrite,
                PixelFormat.Format24bppRgb);

            // lock bitmap data
            BitmapData srcData = srcImage.LockBits(
                rec,
                ImageLockMode.ReadWrite,
                PixelFormat.Format24bppRgb);

            // copy image data
            int srcStride = srcData.Stride;
            int dstStride = imageData.Stride;

            unsafe
            {
                byte* dst = (byte*)imageData.Scan0.ToPointer();
                byte* src = (byte*)srcData.Scan0.ToPointer();

                for (int y = 0; y < height; y++)
                {
                    memcpy(dst, src, dstStride);
                    dst += dstStride;
                    src += srcStride;
                }
            }
            // unlock bitmap data
            image.UnlockBits(imageData);
            srcImage.UnlockBits(srcData);
            return image;
        }
    }
}
